package edu.snake.implement.service;

import edu.snake.core.model.character.Character;
import edu.snake.core.service.ThreadPoolService;
import edu.snake.implement.ConfigConstant;

import java.util.ArrayList;
import java.util.List;


public class ThreadPoolServiceImpl implements ThreadPoolService {

    private final List<ThreadEx> threadPool;

    public ThreadPoolServiceImpl() {
        threadPool = new ArrayList<ThreadEx>(ConfigConstant.frogCount + 1);
    }

    @Override
    public void startThreads() {
        for (ThreadEx threadEx : threadPool) {
            threadEx.start();
        }
    }

    @Override
    public void stopThreads() {
        for (ThreadEx threadEx : threadPool) {
            threadEx.stop();
        }
    }

    @Override
    public void removeCharacter(Character character) {
        ThreadEx result = null;
        for (ThreadEx threadEx : threadPool) {
            if (threadEx.character == character) {
                result = threadEx;
                break;
            }
        }
        if (result != null) {
            while (result.isRunning()) {
                result.stop();
            }
            threadPool.remove(result);
        }
    }

    @Override
    public void pauseThreads() {
        for (ThreadEx threadEx : threadPool) {
            if (threadEx.isRunning()) {
                threadEx.stop();
            } else {
                threadEx.start();
            }
        }
    }

    @Override
    public void addCharacter(Character character, int delay) {
        boolean willNeedRun = false;
        if (threadPool.size() != 0) {
            for (ThreadEx threadEx : threadPool) {
                if (threadEx.isRunning()) {
                    willNeedRun = true;
                    break;
                }
            }
        }
        ThreadEx threadEx = new ThreadEx(character, delay);
        threadPool.add(threadEx);
        if (willNeedRun) {
            threadEx.start();
        }
    }


    private class ThreadEx {
        private Thread t;
        private final Runnable runnable;
        private final Character character;
        private volatile boolean running;


        private ThreadEx(Character character, int delay) {
            this.character = character;
            this.runnable = getRunnable(character, delay);
        }

        private void start() {
            running = true;
            if (t == null) {
                t = new Thread(runnable);
                t.setName("Thread".concat("  ").concat(character.toString()));
                t.start();
            }
        }

        private void stop() {
            running = false;
            t = null;
        }

        public boolean isRunning() {
            return running;
        }


        private Runnable getRunnable(final Character character, final int delay) {
            return new Runnable() {
                @Override
                public void run() {
                    while (running) {
                        if (character.isAlive()) {
                            character.move();
                        }
                        try {
                            Thread.sleep(delay);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
        }
    }
}
